package com.example.service.pet.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.example.config.ProjectProperties;
import com.example.dto.business.PetPhotoBusinessDTO;
import com.example.dto.request.pet.PersonalPetRequestDTO;
import com.example.dto.business.PetBriefInfoBusinessDTO;
import com.example.exception.db.DeleteException;
import com.example.exception.InsertException;
import com.example.exception.db.UpdateException;
import com.example.exception.pet.PetNotOwnedException;
import com.example.mapper.CollarMapper;
import com.example.mapper.PetMapper;
import com.example.mapper.PetPhotoMapper;
import com.example.mapper.RailingMapper;
import com.example.pojo.Pet;
import com.example.pojo.PetPhoto;
import com.example.dto.business.PetBusinessDTO;
import com.example.service.pet.PersonalPetService;
import com.example.vo.pet.RailingDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * @author Lexin Huang
 */
@Slf4j
@Service
public class PersonalPetServiceImpl extends ServiceImpl<PetMapper, Pet> implements PersonalPetService {

    private final String FILE_RESOURCE_PATH_SEPARATOR;

    private final String AVATAR_DIRECTORY_PATH;

    private final String[] SUPPORTED_AVATAR_TYPES;

    private final String AVATAR_URL_PREFIX;

    private final String DEFAULT_AVATAR_URL;

    private final String DEFAULT_PET_INTRODUCTION;

    private final RailingMapper railingMapper;

    private final CollarMapper collarMapper;

    private final PetPhotoMapper petPhotoMapper;

    public PersonalPetServiceImpl(ProjectProperties projectProperties, RailingMapper railingMapper,
                                  CollarMapper collarMapper, PetPhotoMapper petPhotoMapper) {
        this.FILE_RESOURCE_PATH_SEPARATOR = projectProperties.getFile().getResourcePathSeparator();
        this.AVATAR_URL_PREFIX = projectProperties.getPetInfo().getAvatar().getUrlPrefix();
        this.AVATAR_DIRECTORY_PATH = projectProperties.getPetInfo().getAvatar().getDirectoryPath();
        this.SUPPORTED_AVATAR_TYPES = projectProperties.getPetInfo().getAvatar().getSupportedTypes();
        this.DEFAULT_AVATAR_URL = projectProperties.getPetInfo().getAvatar().getDefaultAvatarUrl();
        this.DEFAULT_PET_INTRODUCTION = projectProperties.getPetInfo().getProfile().getDefaultIntroduction();
        this.railingMapper = railingMapper;
        this.collarMapper = collarMapper;
        this.petPhotoMapper = petPhotoMapper;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer addPet(Integer userId, PersonalPetRequestDTO petDTO) {
        Pet pet = new Pet();
        pet.setName(petDTO.getPetName());
        pet.setBreed(petDTO.getPetBreed());
        pet.setUserId(userId);
        pet.setPortraitPath(DEFAULT_AVATAR_URL);
        pet.setOvert(petDTO.getOvert());
        if (Strings.isEmpty(petDTO.getPetIntroduction())) {
            pet.setIntroduction(DEFAULT_PET_INTRODUCTION);
        } else {
            pet.setIntroduction(petDTO.getPetIntroduction());
        }
        if (!save(pet)) {
            throw new InsertException("出错了! 添加宠物失败! 请稍后再试! 如仍遇到该问题, 请联系我们!");
        }
        return pet.getId();
    }

    @Transactional(rollbackFor = UpdateException.class)
    @Override
    public void modifyPetProfile(Integer userId, Integer petId, PersonalPetRequestDTO petDTO) {
        Pet pet = getUserPet(userId, petId);
        pet.setOvert(petDTO.getOvert());
        pet.setName(petDTO.getPetName());
        pet.setIntroduction(petDTO.getPetIntroduction());
        pet.setBreed(petDTO.getPetBreed());
        try {
            if (!updateById(pet)) {
                throw new UpdateException("更新宠物失败! 请稍后再试!");
            }
        } catch (DuplicateKeyException e) {
            throw new UpdateException("该这个名称已经被用过了, 换一个试试~");
        }
    }

    @Override
    public List<PetBriefInfoBusinessDTO> getPetsBriefInfo(Integer userId) {
        List<Pet> queryRes = baseMapper.selectByUserId(userId);
        if (null == queryRes) {
            return Collections.emptyList();
        }
        List<PetBriefInfoBusinessDTO> res = new ArrayList<>();
        for (Pet pet : queryRes) {
            res.add( new PetBriefInfoBusinessDTO(pet));
        }
        return res;
    }

    @Override
    public PetBusinessDTO getPetDetailedInfo(Integer userId, Integer petId) {
        Pet queryRes = getUserPet(userId, petId);
        PetBusinessDTO dto = new PetBusinessDTO();
        dto.setPetId(queryRes.getId());
        dto.setPetName(queryRes.getName());
        dto.setPetPortraitPath(queryRes.getPortraitPath());
        dto.setPetBreed(queryRes.getBreed());
        dto.setOvert(queryRes.getOvert());
        dto.setUserId(queryRes.getUserId());
        dto.setPetIntroduction(queryRes.getIntroduction());
        List<PetPhoto> petPhotos = petPhotoMapper.selectByPetId(queryRes.getId());
        List<PetPhotoBusinessDTO> photosDTO = new ArrayList<>();
        if (null != petPhotos) {
            for (PetPhoto petPhoto : petPhotos) {
                photosDTO.add(new PetPhotoBusinessDTO(petPhoto));
            }
        }
        List<RailingDTO> railings = Objects.requireNonNullElse(railingMapper.selectFencesInfoByPetId(queryRes.getId()),
                Collections.emptyList());
        dto.setPhotos(photosDTO);
        dto.setRailings(railings);
        return dto;
    }

    @Transactional(rollbackFor = DeleteException.class)
    @Override
    public void removeById(Integer userId, Integer petId) {
        checkPetIsOwned(userId, petId);
        if (!super.removeById(petId)) {
            throw new DeleteException("出错了,删除宠物失败!请稍后再试!");
        }
    }



    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addPetPhotos(Integer userId, Integer petId, MultipartFile[] photos) throws InsertException {
        checkPetIsOwned(userId, petId);
        List<String> photosUrl = upload(photos);
        for (String photoUrl : photosUrl) {
            PetPhoto petPhoto = new PetPhoto();
            petPhoto.setPhotoUrl(photoUrl);
            petPhoto.setPetId(petId);
            if (!SqlHelper.retBool(petPhotoMapper.insert(petPhoto))) {
                throw new InsertException("上传宠物图片失败!请稍后再试!");
            }

        }
    }

    @Override
    public String getPetCollarIp(Integer userId, Integer petId) {
        checkPetIsOwned(userId, petId);
        return Objects.requireNonNullElse(collarMapper.selectCollarIpByPetId(petId), "");
    }


    @Transactional(rollbackFor = UpdateException.class)
    @Override
    public String replaceAvatar(Integer petId, Integer userId, MultipartFile image) {
        Pet pet = getUserPet(userId, petId);
        String original = pet.getPortraitPath();
        List<String> imagesUrl = upload(new MultipartFile[]{image});
        String current = imagesUrl.get(0);
        pet.setPortraitPath(current);
        if (!updateById(pet)) {
            deleteFileByUrl(current);
            throw new UpdateException("更新宠物头像失败!");
        }
        removeAvatarIfNotDefault(original);
        return current;
    }

    private Pet getUserPet(Integer userId, Integer petId) {
        Pet pet = getById(petId);
        if (null == pet || !pet.getUserId().equals(userId)) {
            throw new PetNotOwnedException();
        }
        return pet;
    }

    private void checkPetIsOwned(Integer userId, Integer petId) {
        Pet pet = getById(petId);
        if (null == pet || !pet.getUserId().equals(userId)) {
            throw new PetNotOwnedException();
        }
    }

    @Override
    public String getDirectoryPathSeparator() {
        return this.FILE_RESOURCE_PATH_SEPARATOR;
    }

    @Override
    public String getFileUrlPrefix() {
        return this.AVATAR_URL_PREFIX;
    }

    @Override
    public String getStorageDirectoryPath() {
        return this.AVATAR_DIRECTORY_PATH;
    }

    @Override
    public boolean needToRemove(String avatarUrl) {
        return !this.DEFAULT_AVATAR_URL.equals(avatarUrl);
    }

    @Override
    public String[] getSupportedFileTypeNames() {
        return this.SUPPORTED_AVATAR_TYPES;
    }

}
